package com.pine.app.module.security.oauth.config;

import com.google.common.collect.Sets;
import com.pine.app.module.security.oauth.provider.AuthenticationManager;
import com.pine.app.module.security.oauth.provider.OAuthAuthenticationManager;
import com.pine.app.module.security.oauth.handler.FrameworkEndpointHandlerMapping;
import com.pine.app.module.security.oauth.handler.Oauth2Handler;
import com.pine.app.module.security.oauth.plugin.impl.loginTGT.InMemoryOauthTgtService;
import com.pine.app.module.security.oauth.plugin.impl.loginTGT.LoginAPITGTPlugin;
import com.pine.app.module.security.oauth.plugin.impl.loginTGT.LoginPageTGTPlugin;
import com.pine.app.module.security.oauth.plugin.impl.loginTGT.OauthTgtService;
import com.pine.app.module.security.oauth.plugin.impl.validateParams.ValidateParamsPlugin;
import com.pine.app.module.security.oauth.config.properties.ClientDetail;
import com.pine.app.module.security.oauth.config.properties.ClientDetailsProperties;
import com.pine.app.module.security.oauth.config.properties.OAuth2Properties;
import com.pine.app.module.security.oauth.provider.authrizationCode.AuthenticationCodeService;
import com.pine.app.module.security.oauth.provider.authrizationCode.AuthenticationCodeServiceImpl;
import com.pine.app.module.security.oauth.provider.authrizationCode.AuthenticationCodeStore;
import com.pine.app.module.security.oauth.provider.authrizationCode.InMemoryAuthenticationCodeStore;
import com.pine.app.module.security.oauth.provider.client.BaseClient;
import com.pine.app.module.security.oauth.provider.client.ClientDetailsService;
import com.pine.app.module.security.oauth.provider.client.service.impl.InMemoryClientDetailsService;
import com.pine.app.module.security.oauth.provider.token.AccessTokenService;
import com.pine.app.module.security.oauth.provider.token.AccessTokenServiceImpl;
import com.pine.app.module.security.oauth.provider.token.store.InMemoryTokenStore;
import com.pine.app.module.security.oauth.provider.token.store.TokenStore;
import com.pine.app.module.security.oauth.support.client.ClientCredentialsValidator;
import com.pine.app.module.security.oauth.support.code.AuthorizationCodeValidator;
import com.pine.app.module.security.oauth.support.password.PasswordValidator;
import com.pine.app.module.security.oauth.support.refresh.RefreshTokenValidator;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfigureAfter;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Conditional;
import org.springframework.context.annotation.Configuration;

import java.util.Collection;
import java.util.HashMap;

/**
 * 基础配置类
 *
 * @author xiaoyuan
 * @create 2019/9/30 16:29
 **/

@Configuration
@Conditional(EnableAuthorizationServerCondition.class)
@Slf4j
public class OAuth2AuthorizationServerConfiguration extends WebSecurityConfiguration {


    private ClientDetailsProperties properties;

    private OAuth2Properties oAuth2Properties;

    public OAuth2AuthorizationServerConfiguration(ClientDetailsProperties properties,OAuth2Properties oAuth2Properties){
        this.properties = properties;
        this.oAuth2Properties = oAuth2Properties;
    }


    @Bean
    @ConditionalOnMissingBean(AuthenticationManager.class)
    public AuthenticationManager authenticationManager() {
        return new OAuthAuthenticationManager();
    }


    @Bean
    public FrameworkEndpointHandlerMapping frameworkEndpointHandlerMapping() {
        return new FrameworkEndpointHandlerMapping();
    }

    @Bean
    public Oauth2Handler oauth2Handler() {
        return new Oauth2Handler();
    }

    @Bean
    @ConditionalOnMissingBean(AuthenticationCodeStore.class)
    public AuthenticationCodeStore authenticationCodeStore(){
        return new InMemoryAuthenticationCodeStore();
    }


    @Bean
    @ConditionalOnMissingBean(AuthenticationCodeService.class)
    public AuthenticationCodeService authenticationCodeService() {
        return new AuthenticationCodeServiceImpl();
    }


    @Bean
    @ConditionalOnMissingBean(TokenStore.class)
    public TokenStore tokenStore(){
        return new InMemoryTokenStore();
    }


    @Bean
    @ConditionalOnMissingBean(AccessTokenService.class)
    public AccessTokenService accessTokenService() {        return new AccessTokenServiceImpl();

    }

    public ClientDetailsService inMemoryClientDetailsService() {
        InMemoryClientDetailsService inMemoryClientDetailsService = new InMemoryClientDetailsService();
        Collection<ClientDetail> list = properties.getClient().values();
        HashMap clientDetailsStore = new HashMap();
        list.forEach(clientDetails -> {
            BaseClient clientDetails1 = new BaseClient();
            clientDetails1.setClientId(clientDetails.getClientId());
            clientDetails1.setClientSecret(clientDetails.getClientSecret());
            clientDetails1.setClientName(clientDetails.getClientName());
            clientDetails1.setScope(Sets.newHashSet(clientDetails.getScopes()));
            clientDetails1.setAuthorizedGrantTypes(Sets.newHashSet(clientDetails.getGrantTypes()));
            clientDetails1.setAccessTokenValiditySeconds(clientDetails.getAccessTokenValiditySeconds());
            clientDetails1.setRefreshTokenValiditySeconds(clientDetails.getRefreshTokenValiditySeconds());
            clientDetails1.setRegisteredRedirectUris(Sets.newHashSet(clientDetails.getRedictUrls()));
            clientDetailsStore.put(clientDetails.getClientId(), clientDetails1);
        });
        inMemoryClientDetailsService.setClientDetailsStore(clientDetailsStore);
        return inMemoryClientDetailsService;
    }
    /**
     * @Description: 默认使用内存方式加载客户端信息
     * @Author: xiaoyuan
     * @Date: 2020/3/19 17:05
     */
    @Bean
    @ConditionalOnMissingBean(ClientDetailsService.class)
    public ClientDetailsService clientDetailsService() {
        return inMemoryClientDetailsService();
    }



    @Configuration
    public  class  PluginConfiguration{


        public LoginAPITGTPlugin loginAPITGTPlugin() {
            return new LoginAPITGTPlugin(oAuth2Properties.getTgt());
        }



        public ValidateParamsPlugin validateParamsPlugin() {
            return new ValidateParamsPlugin();
        }



        public LoginPageTGTPlugin loginPageTGTPlugin() {
            return new LoginPageTGTPlugin();
        }

        @Bean
        @ConditionalOnMissingBean(OauthTgtService.class)
        public OauthTgtService oauthTgtService() {
            return new InMemoryOauthTgtService(oAuth2Properties.getTgt());
        }
    }




    /**
     * @Description: 请求校验器配置类
     * @Author: xiaoyuan
     * @Date: 2020/3/19 17:02
     */
    @AutoConfigureAfter
    @Configuration
    public  class OAuth2RequestValidatorfiguration {

        /**
         * @Description: 密码模式下的校验类
         * @Author: xiaoyuan
         * @Date: 2020/3/6 16:57
         */
        @Bean
        public PasswordValidator passwordValidator() {
            return new PasswordValidator();
        }

        /**
         * @Description: 刷新模式下的校验类
         * @Author: xiaoyuan
         * @Date: 2020/3/6 16:58
         */
        @Bean
        public RefreshTokenValidator refreshTokenValidator() {
            return new RefreshTokenValidator();
        }

        /**
         * @Description: 客户端模式下的校验类
         * @Author: xiaoyuan
         * @Date: 2020/3/6 16:58
         */
        @Bean
        public ClientCredentialsValidator clientCredentialsValidator() {
            return new ClientCredentialsValidator();
        }

        /**
         * @Description: 授权码模式下的校验类
         * @Author: xiaoyuan
         * @Date: 2020/3/6 16:58
         */
        @Bean
        public AuthorizationCodeValidator authorizationCodeValidator() {
            return new AuthorizationCodeValidator();
        }

    }

}
